/*
 * match.c
 *
 *  Created on: Jan 24, 2012
 *      Author: marco
 */

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "match.h"
#include "cars.h"
#include "cars_messaging.h"
#include "comsock.h"
#include "dgraph.h"
#include "queue.h"
#include "shortestpath.h"
#include "worker.h"

/*Variabili extern dichiarate in mgcars*/
extern FILE *logfile;
extern graph_t *map;
extern pthread_mutex_t offers_mtx;
extern pthread_mutex_t requests_mtx;
extern queue *offers;
extern queue *requests;

unsigned int **prec;
volatile sig_atomic_t _alarm = 0;
message_t offer_reply;
message_t req_reply;

//TOGLIERE
int newMessage(char t, char *payload, message_t* m, int dim);

void* match_start(void* p) {

	int cities;
	int i;
	int sig;
	int tmp;

	struct sigaction sigact_match;
	sigset_t match_set;
	siginfo_t match_info;
	struct timespec timeout;

	EC_M1(sigaction(SIGALRM,NULL,&sigact_match));
	sigact_match.sa_handler = sigalarm_handler;
	EC_M1(sigaction(SIGALRM,&sigact_match,NULL));

	//maschera con solo sigalrm
//	sigemptyset(&set);
//	sigaddset(&set,SIGALRM);
//	//aggiungere user1
//	pthread_sigmask(SIG_SETMASK,&set,NULL);

	timeout.tv_sec = SEC_TIMER; //METTERE 30!!!!!!!!!!!!!!!!!!
	timeout.tv_nsec = 0;

	/*Calcolo dei cammini minimi*/
	cities = n_size(map);
	if (cities == -1) {
		//ERRRORE
		//exit?
	}

	prec = malloc(cities * sizeof(int*));
	if (prec == NULL) {
		//ERRRORE
		//exit?

	}

	for (i = 0; i < cities; i++) {
		if (dijkstra(map, i, &(prec[i])) == NULL) { //&prec?
			printf("errore dijk\n");
			//ERRRORE
			//exit?
		}

	}

//int sigwaitinfo(const sigset_t *set, siginfo_t *info);

	// 3 modi per farlo partire
	// sigusr1
	// timer
	// sigterm/sigint

	while (1) { //go
		printf("MATCH CICLO PRINCIPALE\n");
		tmp = sigtimedwait(&match_set, NULL, &timeout);
		printf("sigtimedwait = %d\n", tmp);
		if (errno == EAGAIN) { //
			printf("Timeout,match lavora\n");

			if (offers == NULL || requests == NULL) {
				printf("Richieste/offerte non presenti\n");
				continue;
			}
			printf("match IN FUNZIONE\n");
			matching(offers, requests);
			printf("dopo matching\n");
		}

	}

	printf("fine match\n");

	pthread_exit(NULL);
}

void matching(queue* o, queue *r) {
	/*Controllo su parametri null effettuato a monte*/
	char *pairing_string;
	int pair_len;
	int tmp;
	offer_t *offer;
	request_t *req;
	user *off_user;
	user *req_user;

	char *route;

	queue_node *o_iter;
	queue_node *r_iter;
	queue_node *o_iter_prev;
	queue_node *r_iter_prev;

	o_iter = o->head;
	r_iter = r->head;
	/*Puntatori al nodo precedente della coda da usare per la cancellazione*/
	o_iter_prev = NULL;
	r_iter_prev = NULL;
	//MUTEX LOCK
	/*Si controllano le offerte presenti*/
	while (o_iter) {
		printf("ciclo sulle offerte\n");
		offer = (offer_t*) o_iter->data;
		//si analizza offer, si controlla ogni richiesta pendente
		off_user = offer->provider;
		/*Per ogni offerta in coda si controllano le richieste pendenti*/
		r_iter_prev = NULL;
		r_iter = r->head;
		while (r_iter) {
			req = (request_t*) r_iter->data;
			req_user = req->client;
			if (strcmp(req_user->name, off_user->name) == 0) {/*Si scartano richieste dello stesso utente*/
				r_iter = r_iter->next;
				continue;
			}

			/*Controllo della corrispondenza tra partenza e arrivo di richiesta e offerta*/
			if (offer->from == req->from && offer->to == req->to
					&& offer->seats > 0) {
				offer->seats--;/*Se si hanno ancora posti disponibili si decrementano*/

				/*Corrispondenza trovata*/
				/*Calcolo della rotta e generazione stringa corrispondente*/
				route = shpath_to_string(map, offer->from, offer->to,
						prec[offer->from]);
				//EC SU ROUTE
				pair_len = (LLABEL * 2) + strlen(route) + 2; //forse +1ancora?
				pairing_string = malloc(pair_len);
				snprintf(pairing_string, pair_len, "%s$%s$%s",
						offer->provider->name, req->client->name, route);
				free(route);
				printf("PAIRING STRING !%s!\n", pairing_string);
				/*Si inviano le risposte ai client*/
				newMessage(MSG_SHARE, pairing_string, &offer_reply, pair_len);
				tmp = sendMessage(off_user->sfd, &offer_reply);
				printf("send a offer %d\n", tmp);
				newMessage(MSG_SHARE, pairing_string, &req_reply, pair_len);
				tmp = sendMessage(req_user->sfd, &req_reply);
				printf("send a req %d\n", tmp);
				/*Si decrementa il contatore per le richieste pendenti dell'utente*/
				req_user->pending--;
				/*Si comunica l'eventuale terminazione delle richieste pendenti*/
				if (req_user->pending == 0) {
					printf("invio sharend\n");
					newMessage(MSG_SHAREND, NULL, &req_reply, 0);
					sendMessage(req_user->sfd, &req_reply);
				}
				/*Scrittura dell'accoppiamento nel file di log*/
				fprintf(logfile, "%s\n", pairing_string);
				fflush(logfile);
				free(pairing_string);
				printf("prima di eliminazione\n");
				/*Si elimina la richiesta soddisfatta*/
				/*Eliminazione dalla testa*/
				if (r_iter_prev == NULL) {
					r_iter_prev = r_iter->next;
					r->head = r_iter_prev;


				} else {/*Eliminazione lungo la coda*/
					r_iter_prev->next = r_iter->next;
				}
				free(r_iter->data);
				//free(r_iter);
				printf("dopo free in testa\n");
				r_iter = r_iter_prev->next;
				printf("dopo spostamento iter");
			} //fine if trovato

			else { /*Accoppiamento non trovato si prosegue*/
				r_iter_prev = r_iter;
				r_iter = r_iter->next;
			}



		}/*Fine ciclo sulle richieste*/
		printf("prima del controllo sull'offerta\n");

		/*Se l'offerta è esaurita la si toglie dalla coda*/
		if (offer->seats == 0) {
			if(o_iter_prev == NULL){/*Eliminazione dalla testa*/
				o->head = o_iter->next;
			}
			else { /*Eliminazione lungo la coda*/
				o_iter_prev->next = o_iter->next;

			}
			free(o_iter->data);
			free(o_iter);
			o_iter = o_iter_prev->next;

		}

		else{/*Offerta ancora disponibile, si passa oltre*/
			o_iter_prev = o_iter;
			o_iter = o_iter->next;

		}

		printf("fine ciclo su offerte\n");
	}/*Fine ciclo sulle offerte*/

	printf("fuori da ciclo offer\n");
}

int newMessage(char t, char *payload, message_t* m, int dim) {

	m->type = t;
	if (payload == NULL) {
		m->length = 0;
		return (0);
	}

	m->buffer = payload;
	m->length = dim;

	return (m->length);
}

//TOGLIERE!!
static void sigalarm_handler(int signum) {
	_alarm = 1;
	printf("SIGALARM MATCH!\n");

}

